home *** CD-ROM | disk | FTP | other *** search
- // =================================================================================
- //
- // >>> ⌐ 1996-1997 Microsoft Corporation. All rights reserved. <<<
- //
- // =================================================================================
-
- #include "AXControlHeaders.h"
- #include "VariantUtil.h"
- #include "CJSButtonControl.h"
-
- #pragma mark === CJSButtonControl::Construction & Destruction ===
-
- const Int16 OvalSize = 20;
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::CJSButtonControl
- //=--------------------------------------------------------------------------=
-
- CJSButtonControl::CJSButtonControl(void)
- {
- mScriptClick = false;
- mValue = NewPtrClear(256);
-
- mLastMouseUpTime = ::TickCount() - ::GetDblTime();
-
- // Add support for an outgoing event interface
- AddConnectionPoint(IID_IDispatch);
- }
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::~CJSButtonControl
- //=--------------------------------------------------------------------------=
-
- CJSButtonControl::~CJSButtonControl()
- {
- DisposePtr(mValue);
- }
-
- #pragma mark === CJSButtonControl::IUnknown Interface ===
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IUnknown::QueryInterface
- //=--------------------------------------------------------------------------=
- // Returns a pointer to the specified interface on a component to which a
- // client currently holds an interface pointer.
- //
- STDMETHODIMP
- CJSButtonControl::QueryInterface(REFIID inRefID, void** outObj)
- {
- AXErrorCode Result = E_NOINTERFACE;
- void* pv = nil;
-
- // First try all the interfaces we implement directly
- if ( inRefID == IID_IControl )
- pv = (void*)(IControl* ) this;
- else if ( inRefID == IID_IDispatch )
- pv = (void*)(IDispatch* ) this;
- else
- {
- // CBaseControl
- Result = CBaseControl::QueryInterface(inRefID, outObj);
-
- // CBaseDispatch
- if ( Result == E_NOINTERFACE )
- Result = CBaseDispatch::QueryInterface(inRefID, outObj);
-
- // CBaseCPServer
- if ( Result == E_NOINTERFACE )
- Result = CBaseCPServer::QueryInterface(inRefID, outObj);
-
- if ( Result != E_NOINTERFACE )
- return Result;
- }
-
- *outObj = pv;
-
- // if we got an interface, ref it and return ok
- if ( pv )
- {
- ((IUnknown*) pv)->AddRef();
- Result = S_OK;
- }
-
- return Result;
- }
-
-
- #pragma mark === CJSButtonControl::IControl Interface ===
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IControl::Draw
- //=--------------------------------------------------------------------------=
-
- STDMETHODIMP
- CJSButtonControl::Draw(AXDrawContext* inContext)
- {
- Str255 Name;
- Int16 NameWidth, NameHeight, ButtonWidth, ButtonHeight;
- Rect ButtonRect = inContext->Location;
-
- // Position the Button rect
- InsetRect(&ButtonRect, 5, 5);
-
- // Erase the area
- EraseRoundRect(&ButtonRect, OvalSize, OvalSize);
-
- // Frame the button
- PenSize(2, 2);
- FrameRoundRect(&ButtonRect, OvalSize, OvalSize);
- PenSize(1, 1);
-
- // Center the text
- ::TextFont(applFont);
- ::TextFace(0);
- ::TextSize(12);
- strcpy((Char8*) Name, mValue);
- c2pstr((Char8*) Name);
- NameWidth = ::StringWidth(Name);
- NameHeight = 12;
- ButtonWidth = ButtonRect.right - ButtonRect.left;
- ButtonHeight = ButtonRect.bottom - ButtonRect.top;
- ::MoveTo(ButtonRect.left+ ((ButtonWidth - NameWidth) / 2),
- ButtonRect.top + ((ButtonHeight - NameHeight) / 2 + NameHeight));
-
- // Draw the name
- ::DrawString(Name);
-
- return S_OK;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IControl::DoMouse
- //=--------------------------------------------------------------------------=
-
- STDMETHODIMP
- CJSButtonControl::DoMouse(AXMouseEventType inMouseET, AXPlatformEvent* inEvent)
- {
- #pragma unused (inEvent)
- switch (inMouseET)
- {
- case kAXMouseDown:
- {
- AXDrawContext Context = {kAXBeginPortType};
-
- if ( mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK )
- {
- Rect ButtonRect = Context.Location;
-
- // Position the Button rect
- ::InsetRect(&ButtonRect, 5, 5);
-
- // Do the button behavior
- ::InvertRoundRect(&ButtonRect, OvalSize, OvalSize);
- WaitClick();
- ::InvertRoundRect(&ButtonRect, OvalSize, OvalSize);
-
- // Release the context
- mContainerSiteP->ReleaseContext(&Context);
-
- // Broadcast the event
- Broadcast(IID_IDispatch, kEventOnClick, nil);
- }
-
- break;
- }
-
- }
-
- return S_OK;
- }
-
- #pragma mark === CJSButton::IPersistPropertyBag Override Methods ===
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IPersistPropertyBag::InitNew
- //=--------------------------------------------------------------------------=
- //
- STDMETHODIMP
- CJSButtonControl::InitNew(void)
- {
- // Call the base control to set up defaults for ID, width and height
- CBaseControl::InitNew();
-
- // We can use the property bag interface on the Object Desc
- // to retrieve default property values
- if ( mObjectDesc )
- {
- IPropertyBag* PropertyBag = nil;
-
- mObjectDesc->QueryInterface(IID_IPropertyBag, &PropertyBag);
-
- // if we got a property bag interface, use it to get the property value
- if ( PropertyBag )
- {
- GetValueFromPropertyBag(PropertyBag, nil);
- PropertyBag->Release();
- }
- }
- else // Can't do much else than this
- strcpy(mValue, "ClickMe");
-
- return S_OK;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IPersistPropertyBag::Load
- //=--------------------------------------------------------------------------=
- //
- STDMETHODIMP
- CJSButtonControl::Load(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
- {
- AXErrorCode Result = CBaseControl::Load(PropertyBag, ErrorLog);
-
- GetValueFromPropertyBag(PropertyBag, ErrorLog);
-
- return S_OK;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IPersistPropertyBag::Save
- //=--------------------------------------------------------------------------=
- //
- STDMETHODIMP
- CJSButtonControl::Save(IPropertyBag* PropertyBag, BOOL ClearDirty, BOOL SaveAllProperties)
- {
- #pragma unused(ClearDirty, SaveAllProperties)
-
- AXErrorCode Result = CBaseControl::Save(PropertyBag, ClearDirty, SaveAllProperties);
-
- if ( Result == S_OK )
- {
- VARIANT Var;
-
- // Fill in the variant structure
- VariantInit(&Var);
- VarSetBStr(&Var, mValue);
-
- // Write our value property's value
- Result = PropertyBag->Write("value", &Var);
-
- // Free the variant string
- SysFreeString(Var.n1.n2.n3.bstrVal);
- }
-
- return Result;
- }
-
-
- #pragma mark === CJSButtonControl::IDispatch methods ===
-
- /*****************************************************************/
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IDispatch::GetIDsOfNames
- //=--------------------------------------------------------------------------=
- STDMETHODIMP
- CJSButtonControl::GetIDsOfNames(REFIID inRefID, char** inNames, unsigned int inNameCount,
- LCID inLocaleID, DISPID* outDispID)
- {
- #pragma unused(inRefID)
- #pragma unused(inLocaleID)
-
- AXErrorCode Result = NOERROR;
-
- // Loop through all the names we know about and return the DISPID
- for (int i = 0; i < inNameCount && Result == NOERROR; i++)
- {
- if ( strcmp( inNames[i], "name" ) == 0 )
- outDispID[i] = kPropName;
- else if ( strcmp( inNames[i], "value" ) == 0 )
- outDispID[i] = kPropValue;
- else if ( strcmp( inNames[i], "click" ) == 0 )
- outDispID[i] = kMethodClick;
- else
- outDispID[i] = -1;
-
- if (outDispID[i] == -1)
- Result = DISP_E_UNKNOWNNAME;
- }
-
- return Result;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::IDispatch::Invoke
- //=--------------------------------------------------------------------------=
- STDMETHODIMP
- CJSButtonControl::Invoke(DISPID inDispID, REFIID inRefID, LCID inLocaleID, unsigned short inFlags, DISPPARAMS* inParams,
- VARIANT* outResult, EXCEPINFO* outExcepInfo, unsigned int* outArgErr)
- {
- #pragma unused(inRefID)
- #pragma unused(inLocaleID)
- #pragma unused(outExcepInfo)
- #pragma unused(outArgErr)
-
- AXErrorCode Result = NOERROR;
-
- // Initialize the return result
- VariantInit(outResult);
-
- // if this is a method call
- if (inFlags & DISPATCH_METHOD)
- {
- switch (inDispID)
- {
- case kMethodClick:
- mScriptClick = true;
- DoMouse(kAXMouseDown, nil);
- mScriptClick = false;
- break;
- }
- }
- else if (inFlags & DISPATCH_PROPERTYGET) // if this is a Get Property call
- {
- char* vResult = nil;
-
- switch (inDispID)
- {
- case kPropName: // Return the ID of the control
- {
- char Name[256];
-
- GetID(256, Name);
- outResult->n1.n2.vt = VT_BSTR;
- outResult->n1.n2.n3.bstrVal = SysAllocStringLen(Name, strlen(Name));
- break;
- }
-
- case kPropValue: // Return our current value
- outResult->n1.n2.vt = VT_BSTR;
- outResult->n1.n2.n3.bstrVal = SysAllocStringLen(mValue, strlen(mValue));
- break;
-
- default:
- return DISP_E_MEMBERNOTFOUND;
- }
- }
- else if (inFlags & DISPATCH_PROPERTYPUT) // else if this is a put property call
- {
- // Make sure that we have at least one parameter and that it is either a str or can be made into one
- if (inParams->cArgs < 1)
- return DISP_E_BADPARAMCOUNT;
-
- switch (inDispID)
- {
- case kPropName: // This is a read-only property
- {
- Result = DISP_E_MEMBERNOTFOUND;
- break;
- }
-
- case kPropValue: // Change the current value to the one supplied
- {
- Char8* NewValue = VarGetBStr(inParams->rgvarg);
- AXDrawContext Context;
-
- // Check for oversized value, then copy
- if ( strlen(NewValue) > 255 )
- {
- strncpy(mValue, NewValue, 255);
- mValue[255] = 0;
- }
- else
- strcpy(mValue, NewValue);
-
- // Invalidate the context so the new value will be drawn
- if ( mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK )
- {
- InvalRect(&Context.Location);
- mContainerSiteP->ReleaseContext(&Context);
- }
- break;
- }
-
- default:
- return DISP_E_MEMBERNOTFOUND;
- }
- }
-
- return Result;
- }
-
-
- #pragma mark === CJSButton::CBaseCPServer Override Methods ===
-
- //=-----------------------------------------------------------------------------
- // CJSButtonControl::BroadcastMessage
- // Override of CBaseCPServer::BroadcastMessage
- // Overriding this method allows controls to fire events
- //=-----------------------------------------------------------------------------
- //
- STDMETHODIMP
- CJSButtonControl::BroadcastMessage(REFIID inRefID, Int32 inMessageID, IUnknown* inTarget, void* inUserData)
- {
- #pragma unused (inUserData)
- AXErrorCode err = S_OK;
-
- // if this is the broadcast for the JSButton outgoing event dispatch interface
- if ( inRefID == IID_IDispatch )
- {
- IDispatch* target = (IDispatch*) inTarget; // Should be an IDispatch interface
- DISPID DispID; // DispID from the client
- char* Name = (char*) CoTaskMemAlloc(16); // Allocate memory to hold the name we'll ask for
-
- // Setup the correct name of the event
- switch ( inMessageID )
- {
- case kEventOnClick:
- strcpy(Name, "onClick");
- break;
-
- default:
- err = E_FAIL;
- break;
- }
-
- // if this is legally one of our events,
- // Invoke the event handler
- if ( err == S_OK )
- {
- // if we can find a DISPID for this name
- // invoke the event handler
- if ( (err = target->GetIDsOfNames(IID_NULL, &Name, 1, 0, &DispID)) == S_OK )
- {
- DISPPARAMS dispParams;
- VARIANT dummyResult;
- EXCEPINFO excepInfo;
- unsigned int ArgError = 0;
-
- // Set up for the Invoke call
- dispParams.rgvarg = nil;
- dispParams.rgdispidNamedArgs = NULL;
- dispParams.cArgs = 0;
- dispParams.cNamedArgs = 0;
- memset(&excepInfo, 0, sizeof(EXCEPINFO));
- VariantInit(&dummyResult);
-
- // invoke the event handler
- err = target->Invoke(DispID, IID_NULL, 0, DISPATCH_METHOD, &dispParams, &dummyResult, &excepInfo, &ArgError);
-
- VariantClear(&dummyResult);
- }
- }
-
- // Free the name allocation
- CoTaskMemFree(Name);
- }
-
-
- return err;
- }
-
- #pragma mark === CJSButtonControl::private methods ===
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::WaitClick
- //=--------------------------------------------------------------------------=
-
- void CJSButtonControl::WaitClick(void)
- {
- if ( mScriptClick )
- {
- long FinalTicks;
-
- Delay(120, &FinalTicks);
- }
- else
- while (StillDown()) ;
- }
-
- //=--------------------------------------------------------------------------=
- // CJSButtonControl::GetValueFromPropertyBag
- //=--------------------------------------------------------------------------=
- //
- void CJSButtonControl::GetValueFromPropertyBag(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
- {
- VARIANT v;
-
- // Initialize the variant
- VariantInit(&v);
- v.n1.n2.vt = VT_BSTR;
- v.n1.n2.n3.bstrVal = nil;
-
- // Get the value
- if ( PropertyBag->Read("value", &v, ErrorLog) == S_OK && v.n1.n2.n3.bstrVal)
- {
- char* TempStr = VarGetBStr(&v);
-
- // Assign the string to our member ID
- if ( TempStr )
- {
- Int16 ValueLen = strlen(TempStr);
-
- if (ValueLen > 255)
- ValueLen = 255;
- strncpy(mValue, TempStr, ValueLen);
- }
-
- // Free the Variant string
- SysFreeString(v.n1.n2.n3.bstrVal);
- v.n1.n2.n3.bstrVal = nil;
- }
- else
- strcpy(mValue, "ClickMe");
- }
-
-
-